<p>最近用EVM做了不少智能合约的项目，有lotto，vote，dao等等，说说感受吧。</p>
<ol>
    <li>千万不要用合约写复杂的逻辑，GAS的消耗是你的限制，库的功能是你的限制，VM的性能是你的限制，VM的稳定性也是你的限制。</li>
    <li>可以把现在的合约当成数据库的存储过程，区块链当成数据库来理解，也就是看起来什么都能干，但是如果真的什么都放在里面干，你会死得很难看。</li>
    <li>并行什么的，还是算了吧，不要试图向合约发起并行修改请求，最好的方式是在合约增加批量处理方法或者调用批量处理请求。因为账户的nonce是需要按次增加的，而每次增加1，都需要等到交易打包到区块中。</li>
    <li>千万别用Java来开发与合约的交互，首先Web3j没有完全实现能力（例如批量提交就没有），第二用了Java你还得写前端逻辑，不如直接使用Web3.js，前端直接搞定，所以正确的架构应该是。 &nbsp;client
        -&gt; ETH-Node ，Server -&gt; ETH-Node这样的模式，如果确实需要一点中心化的东西，那么最好也是使用NodeJS，Web3.js是官方出品，而且功能全面。</li>
    <li>做合约的产品，千万别搞复杂的逻辑，害人害己害用户，大家的手续费都老高，而且还不稳定。简单粗暴的产品最好。</li>
    <li>GAS的设计说实话，在外面看还以为牛逼哄哄，一旦自己成为了开发者，就觉得完全限制了你的发挥，合约的发展任重而道远。</li>
    <li>可能区块链合约的发展都进入了一个误区，就是ETH的GAS或者EOS的资源使用计算，不过好在BM是看到了问题的，他在想办法脱离GAS，但是不够彻底，还是有资源消耗给费用的问题，这些都是限制合约发展的东西，应该统统去掉，要什么费用，这样大家都可以自由发挥了。当然，你说不激励节点怎么运作，那就是区块链项目的事情了，你不能激励节点就干掉用户体验，限制你自己的发展空间，所以链外的计算环境现在应该是个不错的方向，沙盒空间，你爱怎么玩就怎么玩。
    </li>
</ol>
<p>后面想到什么再持续更新吧。</p>
<p>一点感悟：当然，我们帮助NULS做的NVM也有一部分是借鉴了EVM的架构和理念，所以EVM有的问题，NVM同样也有，当然NVM不同的地方在于VM的能力更强，这并不是本质的改变，我们会积极思考NVM2.0，从架构上全面的超越现有的合约体系。
</p>
<p>更新1</p>
<ol>
    <li>GAS还是GAS，这次是GAS Limit。如果你帮助用户管理账户，那么一定要注意计算每次与区块链交互的GAS是不同的，GAS
        Limit的设置也不同，你不能统一设置了事，这样会很大，我们把转账也设置成和业务交互一样的GAS Limit，最后结果就是提现小于GAS * GAS
        Limit就直接报告失败，而业务Limit在600万，提现应该只要30万左右就可以了。</li>
    <li>由于区块链的去中心化，打包区块时间限制，所以dapp尽量不要设计有定时任务的那种，否则你就只有使用外部定时来解决了。</li>
    <li>如果是非dapp的标准模式，即client-&gt;chain, server-&gt;chain的模式，而是client-&gt;server
        -&gt;chain的模式，那么就要注意了，geth尽量使用light模式，否则fast你得准备200G+，full你得准备800G+，而且还必须是SSD。最好是对接infura.io，这样你就不需要节点，不过也得注意的是，web3j不支持infura的filters，web3.js的1.0版本全部支持，之前的版本也不支持。
    </li>
    <li>一切都是异步，与区块链交互最好都是异步，所以你的dapp一定要基于异步去设计和考虑，不是每一次调用都能够立刻得到结果，而是需要等待一段时间，可能很短，也可能很长，也可能很长时间后告诉你有错误。</li>
    <li>在合约中设计的struct时注意一点，不能超过16个属性，超过就会报告stack too deep的错误，这是EVM的设计限制的。</li>
    <li>避免在合约中使用多层for循环，如果必须要，保证迭代的数据不要太多，否则GAS费用承受不起</li>
    <li>数据结构的使用十分十分非常非常受限，mapping和array。mapping是无法被删除的，也无法通过for遍历，而array可以通过for遍历，也可以通过delete
        array的方式进行删除。如果你一定要删除mapping，我们只能迂回的去清空mapping的数据，把它设置成不要的情况，例如{a-&gt;1,b-&gt;2}，清空后面的数字为一个代表无意义的数字，例如{a-&gt;-1,b-&gt;-1}，但是你没法遍历mapping不是，所以怎么清空？这时候一种办法就是利用array再把mapping的key复制一次放在array中，接上面的例子，这个时候你就有个数组存储{a,b},
        array[0] = a， &nbsp;array[1] = b，然后通过遍历这个key数组去清空mapping。</li>
    <li>虽然从链上查询是不消耗GAS的，但是也要考虑机器的性能，总之尽可能的保持产品简单，不要太复杂。</li>
    <li>remix是一个非常好的开发工具，所以尽量用remix去做测试，truffle也不是不行的，但是truffle有时候编译出来的二进制数据和remix编译出来的有些许不同，而remix编译出来的就和你发布到以太坊网络中的二进制是一致的。还有就是，当你发布了合约之后，一定要做code的验证，因为验证前后的bin可能是不同的。我现在的猜想就是合约的编译版本造成的不同，truffle我还不知道怎么确定编译时选择版本，只能配置优化和次数（默认都是200次），remix是可以选择的。这个BIN主要是影响Web3j生成Java合约代理，容易出现一个叫empty(0x)的问题，这种问题一出现，就是因为二进制不对引起的（所以这也是为什么别用web3j的原因，用web3.js是不需要bin就能生成代理的）。
    </li>
</ol>